package controllers.taskboard;

import com.google.gson.Gson;
import models.taskboard.Card;
import play.Logger;
import play.libs.F;
import play.mvc.Http;
import play.mvc.WebSocketController;

import java.util.HashMap;
import java.util.Map;

import static play.mvc.Http.WebSocketEvent.SocketClosed;
import static play.mvc.Http.WebSocketEvent.TextFrame;

/**
 * @author slukjanov
 */
public class TaskBoardWS extends WebSocketController {

    public static final Map<Long, F.EventStream<Map>> messages2clients
            = new HashMap<Long, F.EventStream<Map>>();

    @SuppressWarnings("unchecked")
    public static void serverToClient() {
        long uid = Long.parseLong(session.get("uid"));
        Logger.debug("[TB] S2C, uid=" + uid);

        F.EventStream<Map> queue = messages2clients.get(uid);
        if (queue == null) {
            queue = new F.EventStream<Map>();
            messages2clients.put(uid, queue);
        }

        for (Card card : Card.<Card>findAll()) {
            Map event = new HashMap();
            event.put("action", "card:add");
            event.put("id", card.id);
            event.put("title", card.title);
            event.put("content", card.content);
            event.put("column", card.column);
            queue.publish(event);
        }

        while (inbound.isOpen()) {
            Map message = await(queue.nextEvent());
            Logger.debug("[TB] S2C, sending: " + message);
            outbound.sendJson(message);
        }
    }

    @SuppressWarnings("unchecked")
    public static void clientToServer() {
        long uid = Long.parseLong(session.get("uid"));
        Logger.debug("[TB] C2S, uid=" + uid);

        while (inbound.isOpen()) {
            Http.WebSocketEvent e = await(inbound.nextEvent());
            for (String msg : TextFrame.match(e)) {
                Map message = new Gson().fromJson(msg, Map.class);
                String action = (String) message.get("action");

                if ("card:add".equals(action)) {
                    Card card = new Card(
                            (String) message.get("title"),
                            (String) message.get("content"),
                            (String) message.get("column")
                    );
                    card.save();
                    message.put("id", card.id);
                } else if ("card:remove".equals(action)) {
                    Card card = Card.findById(Long.parseLong((String) message.get("id")));
                    if (card != null) {
                        card.delete();
                    } else {
                        message = null;
                    }
                } else if ("card:update".equals(action)) {
                    Card card = Card.findById(Long.parseLong((String) message.get("id")));
                    if (card != null) {
                        String title = (String) message.get("title");
                        if (title != null) {
                            card.title = title;
                        }

                        String content = (String) message.get("content");
                        if (content != null) {
                            card.content = content;
                        }

                        card.save();
                    } else {
                        message = null;
                    }
                } else if ("card:move".equals(action)) {
                    Card card = Card.findById(Long.parseLong((String) message.get("id")));
                    if (card != null) {
                        card.column = (String) message.get("column");
                        card.save();
                    } else {
                        message = null;
                    }
                } else {
                    Logger.warn("Action " + action + " isn't supported, message: " + message);
                    message = null;
                }

                if (message != null) {
                    synchronized (messages2clients) {
                        for (Map.Entry<Long, F.EventStream<Map>> entry :
                                messages2clients.entrySet()) {
                            entry.getValue().publish(message);
                        }
                    }
                }
            }
            for (Http.WebSocketClose close : SocketClosed.match(e)) {
                Logger.debug("Disconnected");
//                messages2clients.remove(uid);
            }
        }
    }

}
